#include <websocketpp/config/asio_client.hpp>
#include <websocketpp/client.hpp>
#include <iostream>
#include <string>
#include <thread>
#include <unordered_map>
#include <curl/curl.h>
#include <openssl/hmac.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/buffer.h>
#include <nlohmann/json.hpp>
#include "fmtlog.h"
#include "BinanceArbitrage.h"


class BinanceArbitrageBot :public BinanceArbitrage{
public:
    BinanceArbitrageBot(){
        // 肯尼亚
        apiKey = "W1Z5h7RydJ8CNI40azIXOJKVudRLfawy3k8jEdbh0sfU74yHQzVr5a78IU2E2lRV";
        secretKey = "ZMvkc39AOccvuxLnREzFPx7UZY11grocC08qO8R1lSe7L5yGyyZyq4WlwxF0u0gr";
        // 主号
        //std::string apiKey = "AKsErRm5bhMu9DEYewQi6wYPQFU0pUg9GUKzeuZRvat4P5Mgsu16TZe8JnyYfqIU";
        //std::string secretKey = "sIjzPSLIoxsegfHYTHCbLES0IFsfyIHZrKODNTa9MTZeXICGGazvSMHdqoTBeVUI";
        // 客户
        // std::string apiKey = "J7ZirfnADBBhWgOAMnmGHMO45cxRh92lsuRxAqemxXpMvzh9Ss4XtIEtVmAQ3y5G";
        // std::string secretKey = "jtgvjaZrXRGv3xP7pJqdZCnsqA9S12UE8NGurykh3Wc01y27XHa048aTQ3aYx1Sw";
    }

    void on_trade_message(websocketpp::connection_hdl hdl, message_ptr msg) {
        //std::cout << "trade"<<msg->get_payload() << std::endl;
        nlohmann::json json_data = nlohmann::json::parse(std::string(msg->get_payload()));
       
        if(json_data["X"] != "FILLED" || json_data["e"] != "executionReport"){
            return;
        }
        if(forward == 1){ // USDT->ADA->USDC->USDT
            if(json_data["s"]=="ADAUSDT" && json_data["S"]=="BUY"){
                std::string ada_amount = std::string(json_data["z"]);
                //std::string ada_amount = getSpotQuantity("ADA");
                std::cout<<"ADA->USDC,ADA:"<<ada_amount<<std::endl;
                //place_order("ADAUSDC","SELL",formatNumber(ada_amount,1),"quantity");
            }
            if(json_data["s"]=="ADAUSDC" && json_data["S"]=="SELL"){
                //std::string usdc_amount = std::string(json_data["Z"]);
                std::string usdc_amount = getSpotQuantity("USDC");
                std::cout<<"USDC->USDT,USDC:"<<usdc_amount<<std::endl;
                //place_order("USDCUSDT","SELL",formatNumber(usdc_amount,-1),"quantity");
            }
        }    
        if(forward == -1){ // USDT->USDC->ADA->USDT
            if(json_data["s"]=="USDCUSDT" && json_data["S"]=="BUY"){
                //std::string usdc_amount = std::string(json_data["z"]);
                std::string usdc_amount = getSpotQuantity("USDC");
                std::cout<<"USDC->ADA,USDC:"<<usdc_amount<<std::endl;
                //place_order("ADAUSDC","BUY",formatNumber(usdc_amount,5),"quoteOrderQty");
            }
            if(json_data["s"]=="ADAUSDC" && json_data["S"]=="BUY"){
                std::string ada_amount = std::string(json_data["z"]);
                //std::string ada_amount = getSpotQuantity("ADA");
                std::cout<<"ADA->USDT,ADA:"<<ada_amount<<std::endl;
                //place_order("ADAUSDT","SELL",formatNumber(ada_amount,1),"quantity");
            }
        }
        count++;
    }

    void on_data_message(websocketpp::connection_hdl hdl, message_ptr msg) {
        nlohmann::json json_data = nlohmann::json::parse(std::string(msg->get_payload()));
        if(json_data["s"] == "ADAUSDT"){
            price_adausdt = std::stod(std::string(json_data["b"]).c_str());
        }else if(json_data["s"] == "USDCUSDT"){
            price_usdcusdt = std::stod(std::string(json_data["a"]).c_str());
        }else if(json_data["s"] == "ADAUSDC"){
            price_adausdc = std::stod(std::string(json_data["a"]).c_str());
        }    
      
        if(!canTrade) return;
        //std::cout << "Received data message: " << msg->get_payload() << std::endl;
        std::cout<<"adausdt:"<<price_adausdt<<" adausdc:"<<price_adausdc<<" usdcusdt"<<price_usdcusdt<<std::endl;
        if(price_adausdc < 0 || price_usdcusdt < 0 || price_adausdt < 0){
            return;
        }
        std::cout<<price_adausdt/price_adausdc/price_usdcusdt<<std::endl;
        if(price_adausdt/price_adausdc/price_usdcusdt > 1.0005){
            //place_order("ADAUSDC","BUY","20",std::to_string(price_adausdt),"quantity");
            //place_order("ADAUSDT","SELL","20",std::to_string(price_adausdc),"quantity");
            //place_order("USDCUSDT","BUY","10",std::to_string(price_usdcusdt),"quantity");
            std::cout<<"adausdt:"<<price_adausdt<<" adausdc:"<<price_adausdc<<" usdcusdt:"<<price_usdcusdt<<std::endl;
            canTrade = false;
            std::this_thread::sleep_for(std::chrono::seconds(3));
            canTrade = true;
            //cancel_all_order();
        }
    }

private:
    bool canTrade = true;
};

int main() {
    // fmtlog::setLogFile("aribitrage_20240807.log");
	// fmtlog::setLogLevel(fmtlog::DBG);
	// fmtlog::startPollingThread(1000000);

    BinanceArbitrageBot bot;
    std::string dataUrl = "wss://stream.binance.com:9443/ws/adausdt@bookTicker/usdcusdt@bookTicker/adausdc@bookTicker";
    std::string tradeUrl = "wss://stream.binance.com/ws/";
    std::thread data_p(&BinanceArbitrageBot::connect_data_ws,&bot,dataUrl);
    std::thread trade_p(&BinanceArbitrageBot::connect_trade_ws,&bot,tradeUrl);
    //std::this_thread::sleep_for(std::chrono::seconds(10));
    //std::thread check_entry(&BinanceArbitrageBot::check_arbitrage,&bot);
    data_p.join();
    trade_p.join();
    //check_entry.join();

    return 0;
}
